/**
 * TinyMCE version 7.7.1 (2025-03-05)
 */

(function() {
  "use strict";

  var global$6 = tinymce.util.Tools.resolve("tinymce.PluginManager");

  const hasProto = (v, constructor, predicate) => {
    var _a;
    if (predicate(v, constructor.prototype)) {
      return true;
    } else {
      return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
    }
  };
  const typeOf = x => {
    const t = typeof x;
    if (x === null) {
      return "null";
    } else if (t === "object" && Array.isArray(x)) {
      return "array";
    } else if (t === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
      return "string";
    } else {
      return t;
    }
  };
  const isType = type => value => typeOf(value) === type;
  const isString = isType("string");
  const isObject = isType("object");
  const isArray = isType("array");
  const isNullable = a => a === null || a === undefined;
  const isNonNullable = a => !isNullable(a);

  class Optional {
    constructor(tag, value) {
      this.tag = tag;
      this.value = value;
    }

    static some(value) {
      return new Optional(true, value);
    }

    static none() {
      return Optional.singletonNone;
    }

    static from(value) {
      return isNonNullable(value) ? Optional.some(value) : Optional.none();
    }

    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }

    isSome() {
      return this.tag;
    }

    isNone() {
      return !this.tag;
    }

    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }

    bind(binder) {
      if (this.tag) {
        return binder(this.value);
      } else {
        return Optional.none();
      }
    }

    exists(predicate) {
      return this.tag && predicate(this.value);
    }

    forall(predicate) {
      return !this.tag || predicate(this.value);
    }

    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }

    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }

    or(replacement) {
      return this.tag ? this : replacement;
    }

    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }

    orThunk(thunk) {
      return this.tag ? this : thunk();
    }

    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }

    getOrNull() {
      return this.tag ? this.value : null;
    }

    getOrUndefined() {
      return this.value;
    }

    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }

    toArray() {
      return this.tag ? [this.value] : [];
    }

    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }

  Optional.singletonNone = new Optional(false);

  const nativePush = Array.prototype.push;
  const each$1 = (xs, f) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      f(x, i);
    }
  };
  const flatten = xs => {
    const r = [];
    for (let i = 0, len = xs.length; i < len; ++i) {
      if (!isArray(xs[i])) {
        throw new Error("Arr.flatten item " + i + " was not an array, input: " + xs);
      }
      nativePush.apply(r, xs[i]);
    }
    return r;
  };

  const Cell = initial => {
    let value = initial;
    const get = () => {
      return value;
    };
    const set = v => {
      value = v;
    };
    return {
      get,
      set
    };
  };

  const keys = Object.keys;
  const hasOwnProperty = Object.hasOwnProperty;
  const each = (obj, f) => {
    const props = keys(obj);
    for (let k = 0, len = props.length; k < len; k++) {
      const i = props[k];
      const x = obj[i];
      f(x, i);
    }
  };
  const get$1 = (obj, key) => {
    return has(obj, key) ? Optional.from(obj[key]) : Optional.none();
  };
  const has = (obj, key) => hasOwnProperty.call(obj, key);

  const option = name => editor => editor.options.get(name);
  const register$2 = editor => {
    const registerOption = editor.options.register;
    registerOption("audio_template_callback", { processor: "function" });
    registerOption("video_template_callback", { processor: "function" });
    registerOption("iframe_template_callback", { processor: "function" });
    registerOption("media_live_embeds", {
      processor: "boolean",
      default: true
    });
    registerOption("media_filter_html", {
      processor: "boolean",
      default: true
    });
    registerOption("media_url_resolver", { processor: "function" });
    registerOption("media_alt_source", {
      processor: "boolean",
      default: true
    });
    registerOption("media_poster", {
      processor: "boolean",
      default: true
    });
    registerOption("media_dimensions", {
      processor: "boolean",
      default: true
    });
  };
  const getAudioTemplateCallback = option("audio_template_callback");
  const getVideoTemplateCallback = option("video_template_callback");
  const getIframeTemplateCallback = option("iframe_template_callback");
  const hasLiveEmbeds = option("media_live_embeds");
  const shouldFilterHtml = option("media_filter_html");
  const getUrlResolver = option("media_url_resolver");
  const hasAltSource = option("media_alt_source");
  const hasPoster = option("media_poster");
  const hasDimensions = option("media_dimensions");

  var global$5 = tinymce.util.Tools.resolve("tinymce.util.Tools");

  var global$4 = tinymce.util.Tools.resolve("tinymce.dom.DOMUtils");

  var global$3 = tinymce.util.Tools.resolve("tinymce.html.DomParser");

  const DOM$1 = global$4.DOM;
  const trimPx = value => value.replace(/px$/, "");
  const getEphoxEmbedData = node => {
    const style = node.attr("style");
    const styles = style ? DOM$1.parseStyle(style) : {};
    return {
      type: "ephox-embed-iri",
      source: node.attr("data-ephox-embed-iri"),
      altsource: "",
      poster: "",
      width: get$1(styles, "max-width").map(trimPx).getOr(""),
      height: get$1(styles, "max-height").map(trimPx).getOr("")
    };
  };
  const htmlToData = (html, schema) => {
    let data = {};
    const parser = global$3({
      validate: false,
      forced_root_block: false
    }, schema);
    const rootNode = parser.parse(html);
    for (let node = rootNode; node; node = node.walk()) {
      if (node.type === 1) {
        const name = node.name;
        if (node.attr("data-ephox-embed-iri")) {
          data = getEphoxEmbedData(node);
          break;
        } else {
          if (!data.source && name === "param") {
            data.source = node.attr("movie");
          }
          if (name === "iframe" || name === "object" || name === "embed" || name === "video" || name === "audio") {
            if (!data.type) {
              data.type = name;
            }
            data = global$5.extend(node.attributes.map, data);
          }
          if (name === "source") {
            if (!data.source) {
              data.source = node.attr("src");
            } else if (!data.altsource) {
              data.altsource = node.attr("src");
            }
          }
          if (name === "img" && !data.poster) {
            data.poster = node.attr("src");
          }
        }
      }
    }
    data.source = data.source || data.src || "";
    data.altsource = data.altsource || "";
    data.poster = data.poster || "";
    return data;
  };

  const guess = url => {
    var _a;
    const mimes = {
      mp3: "audio/mpeg",
      m4a: "audio/x-m4a",
      wav: "audio/wav",
      mp4: "video/mp4",
      webm: "video/webm",
      ogg: "video/ogg",
      swf: "application/x-shockwave-flash"
    };
    const fileEnd = (_a = url.toLowerCase().split(".").pop()) !== null && _a !== void 0 ? _a : "";
    return get$1(mimes, fileEnd).getOr("");
  };

  var global$2 = tinymce.util.Tools.resolve("tinymce.html.Node");

  var global$1 = tinymce.util.Tools.resolve("tinymce.html.Serializer");

  const Parser = (schema, settings = {}) => global$3({
    forced_root_block: false,
    validate: false,
    allow_conditional_comments: true,
    ...settings
  }, schema);

  const DOM = global$4.DOM;
  const addPx = value => /^[0-9.]+$/.test(value) ? value + "px" : value;
  const updateEphoxEmbed = (data, node) => {
    const style = node.attr("style");
    const styleMap = style ? DOM.parseStyle(style) : {};
    if (isNonNullable(data.width)) {
      styleMap["max-width"] = addPx(data.width);
    }
    if (isNonNullable(data.height)) {
      styleMap["max-height"] = addPx(data.height);
    }
    node.attr("style", DOM.serializeStyle(styleMap));
  };
  const sources = [
    "source",
    "altsource"
  ];
  const updateHtml = (html, data, updateAll, schema) => {
    let numSources = 0;
    let sourceCount = 0;
    const parser = Parser(schema);
    parser.addNodeFilter("source", nodes => numSources = nodes.length);
    const rootNode = parser.parse(html);
    for (let node = rootNode; node; node = node.walk()) {
      if (node.type === 1) {
        const name = node.name;
        if (node.attr("data-ephox-embed-iri")) {
          updateEphoxEmbed(data, node);
          break;
        } else {
          switch (name) {
            case "video":
            case "object":
            case "embed":
            case "img":
            case "iframe":
              if (data.height !== undefined && data.width !== undefined) {
                node.attr("width", data.width);
                node.attr("height", data.height);
              }
              break;
          }
          if (updateAll) {
            switch (name) {
              case "video":
                node.attr("poster", data.poster);
                node.attr("src", null);
                for (let index = numSources; index < 2; index++) {
                  if (data[sources[index]]) {
                    const source = new global$2("source", 1);
                    source.attr("src", data[sources[index]]);
                    source.attr("type", data[sources[index] + "mime"] || null);
                    node.append(source);
                  }
                }
                break;
              case "iframe":
                node.attr("src", data.source);
                break;
              case "object":
                const hasImage = node.getAll("img").length > 0;
                if (data.poster && !hasImage) {
                  node.attr("src", data.poster);
                  const img = new global$2("img", 1);
                  img.attr("src", data.poster);
                  img.attr("width", data.width);
                  img.attr("height", data.height);
                  node.append(img);
                }
                break;
              case "source":
                if (sourceCount < 2) {
                  node.attr("src", data[sources[sourceCount]]);
                  node.attr("type", data[sources[sourceCount] + "mime"] || null);
                  if (!data[sources[sourceCount]]) {
                    node.remove();
                    continue;
                  }
                }
                sourceCount++;
                break;
              case "img":
                if (!data.poster) {
                  node.remove();
                }
                break;
            }
          }
        }
      }
    }
    return global$1({}, schema).serialize(rootNode);
  };

  const urlPatterns = [
    {
      regex: /youtu\.be\/([\w\-_\?&=.]+)/i,
      type: "iframe",
      w: 560,
      h: 314,
      url: "www.youtube.com/embed/$1",
      allowFullscreen: true
    },
    {
      regex: /youtube\.com(.+)v=([^&]+)(&([a-z0-9&=\-_]+))?/i,
      type: "iframe",
      w: 560,
      h: 314,
      url: "www.youtube.com/embed/$2?$4",
      allowFullscreen: true
    },
    {
      regex: /youtube.com\/embed\/([a-z0-9\?&=\-_]+)/i,
      type: "iframe",
      w: 560,
      h: 314,
      url: "www.youtube.com/embed/$1",
      allowFullscreen: true
    },
    {
      regex: /vimeo\.com\/([0-9]+)\?h=(\w+)/,
      type: "iframe",
      w: 425,
      h: 350,
      url: "player.vimeo.com/video/$1?h=$2&title=0&byline=0&portrait=0&color=8dc7dc",
      allowFullscreen: true
    },
    {
      regex: /vimeo\.com\/(.*)\/([0-9]+)\?h=(\w+)/,
      type: "iframe",
      w: 425,
      h: 350,
      url: "player.vimeo.com/video/$2?h=$3&title=0&amp;byline=0",
      allowFullscreen: true
    },
    {
      regex: /vimeo\.com\/([0-9]+)/,
      type: "iframe",
      w: 425,
      h: 350,
      url: "player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc",
      allowFullscreen: true
    },
    {
      regex: /vimeo\.com\/(.*)\/([0-9]+)/,
      type: "iframe",
      w: 425,
      h: 350,
      url: "player.vimeo.com/video/$2?title=0&amp;byline=0",
      allowFullscreen: true
    },
    {
      regex: /maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,
      type: "iframe",
      w: 425,
      h: 350,
      url: "maps.google.com/maps/ms?msid=$2&output=embed\"",
      allowFullscreen: false
    },
    {
      regex: /dailymotion\.com\/video\/([^_]+)/,
      type: "iframe",
      w: 480,
      h: 270,
      url: "www.dailymotion.com/embed/video/$1",
      allowFullscreen: true
    },
    {
      regex: /dai\.ly\/([^_]+)/,
      type: "iframe",
      w: 480,
      h: 270,
      url: "www.dailymotion.com/embed/video/$1",
      allowFullscreen: true
    }
  ];
  const getProtocol = url => {
    const protocolMatches = url.match(/^(https?:\/\/|www\.)(.+)$/i);
    if (protocolMatches && protocolMatches.length > 1) {
      return protocolMatches[1] === "www." ? "https://" : protocolMatches[1];
    } else {
      return "https://";
    }
  };
  const getUrl = (pattern, url) => {
    const protocol = getProtocol(url);
    const match = pattern.regex.exec(url);
    let newUrl = protocol + pattern.url;
    if (isNonNullable(match)) {
      for (let i = 0; i < match.length; i++) {
        newUrl = newUrl.replace("$" + i, () => match[i] ? match[i] : "");
      }
    }
    return newUrl.replace(/\?$/, "");
  };
  const matchPattern = url => {
    const patterns = urlPatterns.filter(pattern => pattern.regex.test(url));
    if (patterns.length > 0) {
      return global$5.extend({}, patterns[0], { url: getUrl(patterns[0], url) });
    } else {
      return null;
    }
  };

  const getIframeHtml = (data, iframeTemplateCallback) => {
    if (iframeTemplateCallback) {
      return iframeTemplateCallback(data);
    } else {
      const allowFullscreen = data.allowfullscreen ? " allowFullscreen=\"1\"" : "";
      return "<iframe src=\"" + data.source + "\" width=\"" + data.width + "\" height=\"" + data.height + "\"" + allowFullscreen + "></iframe>";
    }
  };
  const getFlashHtml = data => {
    let html = "<object data=\"" + data.source + "\" width=\"" + data.width + "\" height=\"" + data.height + "\" type=\"application/x-shockwave-flash\">";
    if (data.poster) {
      html += "<img src=\"" + data.poster + "\" width=\"" + data.width + "\" height=\"" + data.height + "\" />";
    }
    html += "</object>";
    return html;
  };
  const getAudioHtml = (data, audioTemplateCallback) => {
    if (audioTemplateCallback) {
      return audioTemplateCallback(data);
    } else {
      return "<audio controls=\"controls\" src=\"" + data.source + "\">" + (data.altsource ? "\n<source src=\"" + data.altsource + "\"" + (data.altsourcemime ? " type=\"" + data.altsourcemime + "\"" : "") + " />\n" : "") + "</audio>";
    }
  };
  const getVideoHtml = (data, videoTemplateCallback) => {
    if (videoTemplateCallback) {
      return videoTemplateCallback(data);
    } else {
      return "<video width=\"" + data.width + "\" height=\"" + data.height + "\"" + (data.poster ? " poster=\"" + data.poster + "\"" : "") + " controls=\"controls\">\n" + "<source src=\"" + data.source + "\"" + (data.sourcemime ? " type=\"" + data.sourcemime + "\"" : "") + " />\n" + (data.altsource ? "<source src=\"" + data.altsource + "\"" + (data.altsourcemime ? " type=\"" + data.altsourcemime + "\"" : "") + " />\n" : "") + "</video>";
    }
  };
  const dataToHtml = (editor, dataIn) => {
    var _a;
    const data = global$5.extend({}, dataIn);
    if (!data.source) {
      global$5.extend(data, htmlToData((_a = data.embed) !== null && _a !== void 0 ? _a : "", editor.schema));
      if (!data.source) {
        return "";
      }
    }
    if (!data.altsource) {
      data.altsource = "";
    }
    if (!data.poster) {
      data.poster = "";
    }
    data.source = editor.convertURL(data.source, "source");
    data.altsource = editor.convertURL(data.altsource, "source");
    data.sourcemime = guess(data.source);
    data.altsourcemime = guess(data.altsource);
    data.poster = editor.convertURL(data.poster, "poster");
    const pattern = matchPattern(data.source);
    if (pattern) {
      data.source = pattern.url;
      data.type = pattern.type;
      data.allowfullscreen = pattern.allowFullscreen;
      data.width = data.width || String(pattern.w);
      data.height = data.height || String(pattern.h);
    }
    if (data.embed) {
      return updateHtml(data.embed, data, true, editor.schema);
    } else {
      const audioTemplateCallback = getAudioTemplateCallback(editor);
      const videoTemplateCallback = getVideoTemplateCallback(editor);
      const iframeTemplateCallback = getIframeTemplateCallback(editor);
      data.width = data.width || "300";
      data.height = data.height || "150";
      global$5.each(data, (value, key) => {
        data[key] = editor.dom.encode("" + value);
      });
      if (data.type === "iframe") {
        return getIframeHtml(data, iframeTemplateCallback);
      } else if (data.sourcemime === "application/x-shockwave-flash") {
        return getFlashHtml(data);
      } else if (data.sourcemime.indexOf("audio") !== -1) {
        return getAudioHtml(data, audioTemplateCallback);
      } else {
        return getVideoHtml(data, videoTemplateCallback);
      }
    }
  };

  const isMediaElement = element => element.hasAttribute("data-mce-object") || element.hasAttribute("data-ephox-embed-iri");
  const setup$2 = editor => {
    editor.on("mousedown", e => {
      const previewObj = editor.dom.getParent(e.target, ".mce-preview-object");
      if (previewObj && editor.dom.getAttrib(previewObj, "data-mce-selected") === "2") {
        e.stopImmediatePropagation();
      }
    });
    editor.on("click keyup touchend", () => {
      const selectedNode = editor.selection.getNode();
      if (selectedNode && editor.dom.hasClass(selectedNode, "mce-preview-object")) {
        if (editor.dom.getAttrib(selectedNode, "data-mce-selected")) {
          selectedNode.setAttribute("data-mce-selected", "2");
        }
      }
    });
    editor.on("ObjectResized", e => {
      const target = e.target;
      if (target.getAttribute("data-mce-object")) {
        let html = target.getAttribute("data-mce-html");
        if (html) {
          html = unescape(html);
          target.setAttribute("data-mce-html", escape(updateHtml(html, {
            width: String(e.width),
            height: String(e.height)
          }, false, editor.schema)));
        }
      }
    });
  };

  const cache = {};
  const embedPromise = (data, dataToHtml, handler) => {
    return new Promise((res, rej) => {
      const wrappedResolve = response => {
        if (response.html) {
          cache[data.source] = response;
        }
        return res({
          url: data.source,
          html: response.html ? response.html : dataToHtml(data)
        });
      };
      if (cache[data.source]) {
        wrappedResolve(cache[data.source]);
      } else {
        handler({ url: data.source }).then(wrappedResolve).catch(rej);
      }
    });
  };
  const defaultPromise = (data, dataToHtml) => Promise.resolve({
    html: dataToHtml(data),
    url: data.source
  });
  const loadedData = editor => data => dataToHtml(editor, data);
  const getEmbedHtml = (editor, data) => {
    const embedHandler = getUrlResolver(editor);
    return embedHandler ? embedPromise(data, loadedData(editor), embedHandler) : defaultPromise(data, loadedData(editor));
  };
  const isCached = url => has(cache, url);

  const extractMeta = (sourceInput, data) => get$1(data, sourceInput).bind(mainData => get$1(mainData, "meta"));
  const getValue = (data, metaData, sourceInput) => prop => {
    const getFromData = () => get$1(data, prop);
    const getFromMetaData = () => get$1(metaData, prop);
    const getNonEmptyValue = c => get$1(c, "value").bind(v => v.length > 0 ? Optional.some(v) : Optional.none());
    const getFromValueFirst = () => getFromData().bind(child => isObject(child) ? getNonEmptyValue(child).orThunk(getFromMetaData) : getFromMetaData().orThunk(() => Optional.from(child)));
    const getFromMetaFirst = () => getFromMetaData().orThunk(() => getFromData().bind(child => isObject(child) ? getNonEmptyValue(child) : Optional.from(child)));
    return { [prop]: (prop === sourceInput ? getFromValueFirst() : getFromMetaFirst()).getOr("") };
  };
  const getDimensions = (data, metaData) => {
    const dimensions = {};
    get$1(data, "dimensions").each(dims => {
      each$1([
        "width",
        "height"
      ], prop => {
        get$1(metaData, prop).orThunk(() => get$1(dims, prop)).each(value => dimensions[prop] = value);
      });
    });
    return dimensions;
  };
  const unwrap = (data, sourceInput) => {
    const metaData = sourceInput && sourceInput !== "dimensions" ? extractMeta(sourceInput, data).getOr({}) : {};
    const get = getValue(data, metaData, sourceInput);
    return {
      ...get("source"),
      ...get("altsource"),
      ...get("poster"),
      ...get("embed"),
      ...getDimensions(data, metaData)
    };
  };
  const wrap = data => {
    const wrapped = {
      ...data,
      source: { value: get$1(data, "source").getOr("") },
      altsource: { value: get$1(data, "altsource").getOr("") },
      poster: { value: get$1(data, "poster").getOr("") }
    };
    each$1([
      "width",
      "height"
    ], prop => {
      get$1(data, prop).each(value => {
        const dimensions = wrapped.dimensions || {};
        dimensions[prop] = value;
        wrapped.dimensions = dimensions;
      });
    });
    return wrapped;
  };
  const handleError = editor => error => {
    const errorMessage = error && error.msg ? "Media embed handler error: " + error.msg : "Media embed handler threw unknown error.";
    editor.notificationManager.open({
      type: "error",
      text: errorMessage
    });
  };
  const getEditorData = editor => {
    const element = editor.selection.getNode();
    const snippet = isMediaElement(element) ? editor.serializer.serialize(element, { selection: true }) : "";
    const data = htmlToData(snippet, editor.schema);
    const getDimensionsOfElement = () => {
      if (isEmbedIframe(data.source, data.type)) {
        const rect = editor.dom.getRect(element);
        return {
          width: rect.w.toString().replace(/px$/, ""),
          height: rect.h.toString().replace(/px$/, "")
        };
      } else {
        return {};
      }
    };
    const dimensions = getDimensionsOfElement();
    return {
      embed: snippet,
      ...data,
      ...dimensions
    };
  };
  const addEmbedHtml = (api, editor) => response => {
    if (isString(response.url) && response.url.trim().length > 0) {
      const html = response.html;
      const snippetData = htmlToData(html, editor.schema);
      const nuData = {
        ...snippetData,
        source: response.url,
        embed: html
      };
      api.setData(wrap(nuData));
    }
  };
  const selectPlaceholder = (editor, beforeObjects) => {
    const afterObjects = editor.dom.select("*[data-mce-object]");
    for (let i = 0; i < beforeObjects.length; i++) {
      for (let y = afterObjects.length - 1; y >= 0; y--) {
        if (beforeObjects[i] === afterObjects[y]) {
          afterObjects.splice(y, 1);
        }
      }
    }
    editor.selection.select(afterObjects[0]);
  };
  const handleInsert = (editor, html) => {
    const beforeObjects = editor.dom.select("*[data-mce-object]");
    editor.insertContent(html);
    selectPlaceholder(editor, beforeObjects);
    editor.nodeChanged();
  };
  const isEmbedIframe = (url, mediaDataType) => isNonNullable(mediaDataType) && mediaDataType === "ephox-embed-iri" && isNonNullable(matchPattern(url));
  const shouldInsertAsNewIframe = (prevData, newData) => {
    const hasDimensionsChanged = (prevData, newData) => prevData.width !== newData.width || prevData.height !== newData.height;
    return hasDimensionsChanged(prevData, newData) && isEmbedIframe(newData.source, prevData.type);
  };
  const submitForm = (prevData, newData, editor) => {
    var _a;
    newData.embed = shouldInsertAsNewIframe(prevData, newData) && hasDimensions(editor) ? dataToHtml(editor, {
      ...newData,
      embed: ""
    }) : updateHtml((_a = newData.embed) !== null && _a !== void 0 ? _a : "", newData, false, editor.schema);
    if (newData.embed && (prevData.source === newData.source || isCached(newData.source))) {
      handleInsert(editor, newData.embed);
    } else {
      getEmbedHtml(editor, newData).then(response => {
        handleInsert(editor, response.html);
      }).catch(handleError(editor));
    }
  };
  const showDialog = editor => {
    const editorData = getEditorData(editor);
    const currentData = Cell(editorData);
    const initialData = wrap(editorData);
    const handleSource = (prevData, api) => {
      const serviceData = unwrap(api.getData(), "source");
      if (prevData.source !== serviceData.source) {
        addEmbedHtml(win, editor)({
          url: serviceData.source,
          html: ""
        });
        getEmbedHtml(editor, serviceData).then(addEmbedHtml(win, editor)).catch(handleError(editor));
      }
    };
    const handleEmbed = api => {
      var _a;
      const data = unwrap(api.getData());
      const dataFromEmbed = htmlToData((_a = data.embed) !== null && _a !== void 0 ? _a : "", editor.schema);
      api.setData(wrap(dataFromEmbed));
    };
    const handleUpdate = (api, sourceInput, prevData) => {
      const dialogData = unwrap(api.getData(), sourceInput);
      const data = shouldInsertAsNewIframe(prevData, dialogData) && hasDimensions(editor) ? {
        ...dialogData,
        embed: ""
      } : dialogData;
      const embed = dataToHtml(editor, data);
      api.setData(wrap({
        ...data,
        embed
      }));
    };
    const mediaInput = [{
      name: "source",
      type: "urlinput",
      filetype: "media",
      label: "Source",
      picker_text: "Browse files"
    }];
    const sizeInput = !hasDimensions(editor) ? [] : [{
      type: "sizeinput",
      name: "dimensions",
      label: "Constrain proportions",
      constrain: true
    }];
    const generalTab = {
      title: "General",
      name: "general",
      items: flatten([
        mediaInput,
        sizeInput
      ])
    };
    const embedTextarea = {
      type: "textarea",
      name: "embed",
      label: "Paste your embed code below:"
    };
    const embedTab = {
      title: "Embed",
      items: [embedTextarea]
    };
    const advancedFormItems = [];
    if (hasAltSource(editor)) {
      advancedFormItems.push({
        name: "altsource",
        type: "urlinput",
        filetype: "media",
        label: "Alternative source URL"
      });
    }
    if (hasPoster(editor)) {
      advancedFormItems.push({
        name: "poster",
        type: "urlinput",
        filetype: "image",
        label: "Media poster (Image URL)"
      });
    }
    const advancedTab = {
      title: "Advanced",
      name: "advanced",
      items: advancedFormItems
    };
    const tabs = [
      generalTab,
      embedTab
    ];
    if (advancedFormItems.length > 0) {
      tabs.push(advancedTab);
    }
    const body = {
      type: "tabpanel",
      tabs
    };
    const win = editor.windowManager.open({
      title: "Insert/Edit Media",
      size: "normal",
      body,
      buttons: [
        {
          type: "cancel",
          name: "cancel",
          text: "Cancel"
        },
        {
          type: "submit",
          name: "save",
          text: "Save",
          primary: true
        }
      ],
      onSubmit: api => {
        const serviceData = unwrap(api.getData());
        submitForm(currentData.get(), serviceData, editor);
        api.close();
      },
      onChange: (api, detail) => {
        switch (detail.name) {
          case "source":
            handleSource(currentData.get(), api);
            break;
          case "embed":
            handleEmbed(api);
            break;
          case "dimensions":
          case "altsource":
          case "poster":
            handleUpdate(api, detail.name, currentData.get());
            break;
        }
        currentData.set(unwrap(api.getData()));
      },
      initialData
    });
  };

  const get = editor => {
    const showDialog$1 = () => {
      showDialog(editor);
    };
    return { showDialog: showDialog$1 };
  };

  const register$1 = editor => {
    const showDialog$1 = () => {
      showDialog(editor);
    };
    editor.addCommand("mceMedia", showDialog$1);
  };

  const checkRange = (str, substr, start) => substr === "" || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
  const startsWith = (str, prefix) => {
    return checkRange(str, prefix, 0);
  };

  var global = tinymce.util.Tools.resolve("tinymce.Env");

  const isLiveEmbedNode = node => {
    const name = node.name;
    return name === "iframe" || name === "video" || name === "audio";
  };
  const getDimension = (node, styles, dimension, defaultValue = null) => {
    const value = node.attr(dimension);
    if (isNonNullable(value)) {
      return value;
    } else if (!has(styles, dimension)) {
      return defaultValue;
    } else {
      return null;
    }
  };
  const setDimensions = (node, previewNode, styles) => {
    const useDefaults = previewNode.name === "img" || node.name === "video";
    const defaultWidth = useDefaults ? "300" : null;
    const fallbackHeight = node.name === "audio" ? "30" : "150";
    const defaultHeight = useDefaults ? fallbackHeight : null;
    previewNode.attr({
      width: getDimension(node, styles, "width", defaultWidth),
      height: getDimension(node, styles, "height", defaultHeight)
    });
  };
  const appendNodeContent = (editor, nodeName, previewNode, html) => {
    const newNode = Parser(editor.schema).parse(html, { context: nodeName });
    while (newNode.firstChild) {
      previewNode.append(newNode.firstChild);
    }
  };
  const createPlaceholderNode = (editor, node) => {
    const name = node.name;
    const placeHolder = new global$2("img", 1);
    retainAttributesAndInnerHtml(editor, node, placeHolder);
    setDimensions(node, placeHolder, {});
    placeHolder.attr({
      "style": node.attr("style"),
      "src": global.transparentSrc,
      "data-mce-object": name,
      "class": "mce-object mce-object-" + name
    });
    return placeHolder;
  };
  const createPreviewNode = (editor, node) => {
    var _a;
    const name = node.name;
    const previewWrapper = new global$2("span", 1);
    previewWrapper.attr({
      "contentEditable": "false",
      "style": node.attr("style"),
      "data-mce-object": name,
      "class": "mce-preview-object mce-object-" + name
    });
    retainAttributesAndInnerHtml(editor, node, previewWrapper);
    const styles = editor.dom.parseStyle((_a = node.attr("style")) !== null && _a !== void 0 ? _a : "");
    const previewNode = new global$2(name, 1);
    setDimensions(node, previewNode, styles);
    previewNode.attr({
      src: node.attr("src"),
      style: node.attr("style"),
      class: node.attr("class")
    });
    if (name === "iframe") {
      previewNode.attr({
        allowfullscreen: node.attr("allowfullscreen"),
        frameborder: "0",
        sandbox: node.attr("sandbox"),
        referrerpolicy: node.attr("referrerpolicy")
      });
    } else {
      const attrs = [
        "controls",
        "crossorigin",
        "currentTime",
        "loop",
        "muted",
        "poster",
        "preload"
      ];
      each$1(attrs, attrName => {
        previewNode.attr(attrName, node.attr(attrName));
      });
      const sanitizedHtml = previewWrapper.attr("data-mce-html");
      if (isNonNullable(sanitizedHtml)) {
        appendNodeContent(editor, name, previewNode, unescape(sanitizedHtml));
      }
    }
    const shimNode = new global$2("span", 1);
    shimNode.attr("class", "mce-shim");
    previewWrapper.append(previewNode);
    previewWrapper.append(shimNode);
    return previewWrapper;
  };
  const retainAttributesAndInnerHtml = (editor, sourceNode, targetNode) => {
    var _a;
    const attribs = (_a = sourceNode.attributes) !== null && _a !== void 0 ? _a : [];
    let ai = attribs.length;
    while (ai--) {
      const attrName = attribs[ai].name;
      let attrValue = attribs[ai].value;
      if (attrName !== "width" && attrName !== "height" && attrName !== "style" && !startsWith(attrName, "data-mce-")) {
        if (attrName === "data" || attrName === "src") {
          attrValue = editor.convertURL(attrValue, attrName);
        }
        targetNode.attr("data-mce-p-" + attrName, attrValue);
      }
    }
    const serializer = global$1({ inner: true }, editor.schema);
    const tempNode = new global$2("div", 1);
    each$1(sourceNode.children(), child => tempNode.append(child));
    const innerHtml = serializer.serialize(tempNode);
    if (innerHtml) {
      targetNode.attr("data-mce-html", escape(innerHtml));
      targetNode.empty();
    }
  };
  const isPageEmbedWrapper = node => {
    const nodeClass = node.attr("class");
    return isString(nodeClass) && /\btiny-pageembed\b/.test(nodeClass);
  };
  const isWithinEmbedWrapper = node => {
    let tempNode = node;
    while (tempNode = tempNode.parent) {
      if (tempNode.attr("data-ephox-embed-iri") || isPageEmbedWrapper(tempNode)) {
        return true;
      }
    }
    return false;
  };
  const placeHolderConverter = editor => nodes => {
    let i = nodes.length;
    let node;
    while (i--) {
      node = nodes[i];
      if (!node.parent) {
        continue;
      }
      if (node.parent.attr("data-mce-object")) {
        continue;
      }
      if (isLiveEmbedNode(node) && hasLiveEmbeds(editor)) {
        if (!isWithinEmbedWrapper(node)) {
          node.replace(createPreviewNode(editor, node));
        }
      } else {
        if (!isWithinEmbedWrapper(node)) {
          node.replace(createPlaceholderNode(editor, node));
        }
      }
    }
  };

  const parseAndSanitize = (editor, context, html) => {
    const getEditorOption = editor.options.get;
    const sanitize = getEditorOption("xss_sanitization");
    const validate = shouldFilterHtml(editor);
    return Parser(editor.schema, {
      sanitize,
      validate
    }).parse(html, { context });
  };

  const setup$1 = editor => {
    editor.on("PreInit", () => {
      const { schema, serializer, parser } = editor;
      const boolAttrs = schema.getBoolAttrs();
      each$1("webkitallowfullscreen mozallowfullscreen".split(" "), name => {
        boolAttrs[name] = {};
      });
      each({ embed: ["wmode"] }, (attrs, name) => {
        const rule = schema.getElementRule(name);
        if (rule) {
          each$1(attrs, attr => {
            rule.attributes[attr] = {};
            rule.attributesOrder.push(attr);
          });
        }
      });
      parser.addNodeFilter("iframe,video,audio,object,embed", placeHolderConverter(editor));
      serializer.addAttributeFilter("data-mce-object", (nodes, name) => {
        var _a;
        let i = nodes.length;
        while (i--) {
          const node = nodes[i];
          if (!node.parent) {
            continue;
          }
          const realElmName = node.attr(name);
          const realElm = new global$2(realElmName, 1);
          if (realElmName !== "audio") {
            const className = node.attr("class");
            if (className && className.indexOf("mce-preview-object") !== -1 && node.firstChild) {
              realElm.attr({
                width: node.firstChild.attr("width"),
                height: node.firstChild.attr("height")
              });
            } else {
              realElm.attr({
                width: node.attr("width"),
                height: node.attr("height")
              });
            }
          }
          realElm.attr({ style: node.attr("style") });
          const attribs = (_a = node.attributes) !== null && _a !== void 0 ? _a : [];
          let ai = attribs.length;
          while (ai--) {
            const attrName = attribs[ai].name;
            if (attrName.indexOf("data-mce-p-") === 0) {
              realElm.attr(attrName.substr(11), attribs[ai].value);
            }
          }
          const innerHtml = node.attr("data-mce-html");
          if (innerHtml) {
            const fragment = parseAndSanitize(editor, realElmName, unescape(innerHtml));
            each$1(fragment.children(), child => realElm.append(child));
          }
          node.replace(realElm);
        }
      });
    });
    editor.on("SetContent", () => {
      const dom = editor.dom;
      each$1(dom.select("span.mce-preview-object"), elm => {
        if (dom.select("span.mce-shim", elm).length === 0) {
          dom.add(elm, "span", { class: "mce-shim" });
        }
      });
    });
  };

  const setup = editor => {
    editor.on("ResolveName", e => {
      let name;
      if (e.target.nodeType === 1 && (name = e.target.getAttribute("data-mce-object"))) {
        e.name = name;
      }
    });
  };

  const onSetupEditable = editor => api => {
    const nodeChanged = () => {
      api.setEnabled(editor.selection.isEditable());
    };
    editor.on("NodeChange", nodeChanged);
    nodeChanged();
    return () => {
      editor.off("NodeChange", nodeChanged);
    };
  };
  const register = editor => {
    const onAction = () => editor.execCommand("mceMedia");
    editor.ui.registry.addToggleButton("media", {
      tooltip: "Insert/edit media",
      icon: "embed",
      onAction,
      onSetup: buttonApi => {
        const selection = editor.selection;
        buttonApi.setActive(isMediaElement(selection.getNode()));
        const unbindSelectorChanged = selection.selectorChangedWithUnbind("img[data-mce-object],span[data-mce-object],div[data-ephox-embed-iri]", buttonApi.setActive).unbind;
        const unbindEditable = onSetupEditable(editor)(buttonApi);
        return () => {
          unbindSelectorChanged();
          unbindEditable();
        };
      }
    });
    editor.ui.registry.addMenuItem("media", {
      icon: "embed",
      text: "Media...",
      onAction,
      onSetup: onSetupEditable(editor)
    });
  };

  var Plugin = () => {
    global$6.add("media", editor => {
      register$2(editor);
      register$1(editor);
      register(editor);
      setup(editor);
      setup$1(editor);
      setup$2(editor);
      return get(editor);
    });
  };

  Plugin();

})();
